package com.bj58.mis.apm.server.kylin.service.impl;

import com.bj58.mis.apm.server.kylin.common.CubeStatsReader;
import com.bj58.mis.apm.server.kylin.mapper.KylinAnalysisMapper;
import com.bj58.mis.apm.server.kylin.model.*;
import com.bj58.mis.apm.server.kylin.service.IKylinAnalysisService;
import com.bj58.mis.apm.server.kylin.util.JsonUtil;
import com.bj58.mis.apm.server.kylin.util.KylinLogUtil;
import com.bj58.mis.apm.server.kylin.util.ModelParseUtil;
import com.bj58.mis.apm.server.kylin.util.ZipUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.*;

/**
 * kylin分析包处理器
 */
@Service
public class KylinAnalysisServiceImpl implements IKylinAnalysisService {

    Log log = LogFactory.getLog(KylinAnalysisServiceImpl.class);

    @Resource
    KylinAnalysisMapper kylinAnalysisMapper;

    @Override
    public void exec(File file){
        if(!file.exists() || file.isDirectory()){
            return;
        }

        //解压缩
        String targetpath = unzipStep(file);

        //读取元数据
        readMetaData(targetpath);

        //读取cube执行jobs
        readJobs(targetpath);

        //读取日志信息
        readLogs(targetpath);

        //读取环境信息
        readEnvironment();

        //删除文件
        deleteFile(targetpath);
    }

    /**
     * step1 解压缩
     * @throws Exception
     */
    private String unzipStep(File file) {
        try {
            String zipfile = file.getAbsolutePath();
            log.info("解压缩：" + zipfile);
            String targetpath = ZipUtil.unzip(zipfile);
            String tmp = file.getName();
            targetpath = targetpath + tmp.substring(0, tmp.length() - 11) + File.separator;
            return targetpath;
        }catch (IOException e){
            throw new RuntimeException(e);
        }
    }

    /**
     * step2 读取元数据
     */
    private void readMetaData(String targetpath){
        Long now = new Date().getTime();
        Map<String, Object> updateparam = new HashMap<>();
        updateparam.put("record_update",now);

        String metaDataPath = targetpath + "metadata" + File.separator;
        Map<String, Project> cubeProjectMap = new HashMap<>();
        Map<String, CubeDesc> cubedescMap = new HashMap<>();
        //处理project.json
        List<Project> projects = ModelParseUtil.readMetaData(metaDataPath + "project" + File.separator, Project.class);
        if(projects != null && projects.size() > 0) {
            projects.forEach(p -> {
                p.deal();
                p.getCubes().forEach(cubename -> {
                    cubeProjectMap.put(cubename, p);
                });
            });
            Map<String, Object> map = new HashMap<>();
            map.put("list",projects);
            map.put("record_update", now);
            kylinAnalysisMapper.saveOrUpdateProject(map);
            kylinAnalysisMapper.updateProject(updateparam);
        }

        //处理cube_desc.json
        List<CubeDesc> cubeDescs = ModelParseUtil.readMetaData(metaDataPath + "cube_desc" + File.separator, CubeDesc.class);
        if(cubeDescs != null && cubeDescs.size() > 0) {
            List<RowKeyDesc> rowkeys = new ArrayList<>();
            cubeDescs.forEach(cd -> {
                cd.deal();
                Project p = cubeProjectMap.get(cd.getName());
                cubedescMap.put(cd.getName(), cd);
                if(p != null){
                    cd.setProject(p);
                }
                rowkeys.addAll(cd.getRowKeyDescs());
                cd.setCuboidScheduler(new CuboidScheduler(cd));
            });

            Map<String, Object> map = new HashMap<>();
            map.put("list",cubeDescs);
            map.put("record_update", now);
            kylinAnalysisMapper.saveOrUpdateCubeDesc(map);
            kylinAnalysisMapper.updateCubeDesc(updateparam);
            Map<String, Object> rowkeymap = new HashMap<>();
            rowkeymap.put("list",rowkeys);
            rowkeymap.put("record_update", now);
            kylinAnalysisMapper.saveOrUpdateRowKeyDesc(rowkeymap);
            kylinAnalysisMapper.updateRowKeyDesc(updateparam);

        }

        //处理cube.json
        List<Cube> cubes = ModelParseUtil.readMetaData(metaDataPath + "cube" + File.separator, Cube.class);
        if(cubes != null && cubes.size() > 0) {
            List<Segment> segments = new ArrayList<>();
            List<Map<String, Object>> rowkeyStats = new ArrayList<>();
            cubes.forEach(c -> {
                c.deal();
                Project p = cubeProjectMap.get(c.getName());
                if(p != null){
                    c.setProject(p);
                }
                CubeDesc cubedesc = cubedescMap.get(c.getName());
                if(cubedesc != null){
                    c.setCubeDesc(cubedesc);
                }
                List<Segment> segs = c.getSegments();
                if(segs != null && segs.size() > 0) {
                    segments.addAll(segs);
                    segs.forEach(s -> {
                        if(s != null && s.getRowkeyStats() != null) {
                            rowkeyStats.addAll(s.getRowkeyStats());
                        }
                    });
                }
            });
            Map<String, Object> map = new HashMap<>();
            map.put("list",cubes);
            map.put("record_update", now);
            kylinAnalysisMapper.saveOrUpdateCube(map);
            kylinAnalysisMapper.updateCube(updateparam);
            kylinAnalysisMapper.saveOrUpdateSegment(segments);
            kylinAnalysisMapper.saveOrUpdateSegmentRS(rowkeyStats);

            //处理seq文件
            List<CubeStatistic> cubeStatistics = new ArrayList<>();
            List<CubeCuboid> cuboidList = new ArrayList<>();
            segments.forEach( seg -> {
                try {
                    File seqfile = new File(metaDataPath + "cube_statistics" + File.separator + seg.getCube().getName() + File.separator + seg.getUuid()+".seq");
                    if(seqfile.exists()){
                        CubeStatsReader statisReader = new CubeStatsReader(seqfile.getAbsolutePath(), seg);
                        CubeStatistic cs = statisReader.build().getCubeStatistic();
                        cubeStatistics.add(cs);
                        cuboidList.addAll(cs.getCuboidList());
                    }else{
                        System.out.println(seqfile.getAbsolutePath());
                    }
                } catch(Exception e){
                    e.printStackTrace();
                    throw new RuntimeException(e);
                }
            });
            kylinAnalysisMapper.saveOrUpdateCubeStatistic(cubeStatistics);
            kylinAnalysisMapper.saveOrUpdateCubeCuboids(cuboidList);
        }



        //处理statistics信息

    }

    /**
     * 读取cube执行jobs
     */
    private void readJobs(String targetpath){
        List<Job> jobs = ModelParseUtil.readMetaData(targetpath + "jobs" + File.separator, Job.class);
        System.out.println(JsonUtil.toString(jobs));
        if(jobs != null && jobs.size() > 0) {
            List<Step> steps = new ArrayList<>();
            jobs.forEach(j -> {
                j.deal();
                j.getSteps().forEach( s -> {
                    s.deal();
                    s.setJob_id(j.getUuid());
                    steps.add(s);
                });
            });
            kylinAnalysisMapper.saveOrUpdateJob(jobs);
            kylinAnalysisMapper.saveOrUpdateJobSteps(steps);
        }
    }

    /**
     * 读取目录下日志文件，遍历查找kylin.log
     * @param targetpath 目录
     */
    private void readLogs(String targetpath){
        File logdir = new File(targetpath + "logs");
        String[] logs = logdir.list();
        for(String log : logs){
            if(log.startsWith("kylin.log")){
                readLogs(new File(logdir, log));
            }
        }


    }

    /**
     * 读取日志文件
     * @param file 日志文件
     */
    private void readLogs(File file){
        List<Map<String, Object>> logs = KylinLogUtil.readQueryInfo(file);
        int pi = 0;
        int len = logs.size();
        while(pi * 100 < len){
            kylinAnalysisMapper.saveOrUpdateQueryLog(logs.subList(pi * 100, Math.min(len, (pi+1) * 100)));
            pi ++;
        }
    }

    /**
     * 读取环境信息
     */
    private void readEnvironment(){

    }

    /**
     * 删除临时文件
     */
    private void deleteFile(String targetpath){
        File file = new File(targetpath);
        if(file.exists()){
            file.delete();
        }
    }

}

